/*********************************************************************************************************
* 模块名称：ADC.c
* 摘    要：ADC模块
* 当前版本：1.0.0
* 作    者：
* 完成日期：2025年04月25日 
* 内    容：
* 注    意：
**********************************************************************************************************
* 取代版本：
* 作    者：
* 完成日期：
* 修改内容:
* 修改文件：
*********************************************************************************************************/

/*********************************************************************************************************
*                                              包含头文件
*********************************************************************************************************/
#include "ADC.h"
#include "gd32f30x_conf.h"
#include "Systick.h"

/*********************************************************************************************************
*                                              宏定义
*********************************************************************************************************/

/*********************************************************************************************************
*                                              枚举结构体
*********************************************************************************************************/

/*********************************************************************************************************
*                                              内部变量定义
*********************************************************************************************************/
static unsigned short s_arrADCData;

static uint16_t adcVol = 0; //读取到的ADC电压值（单位mv）
/*********************************************************************************************************
*                                              内部函数声明
*********************************************************************************************************/
static void ConfigRCU(void);                                        //使能设备时钟
static void ConfigDMA0CH0ForADC0(void);             //配置DMA0通道0
static void ConfigTIMER0(unsigned short arr, unsigned short psc);   //配置TIMER0
static void ConfigADC0(void);                                       //配置ADC0
/*********************************************************************************************************
*                                              内部函数实现
*********************************************************************************************************/

/*********************************************************************************************************
* 函数名称：ConfigRCU
* 函数功能：配置RCU
* 输入参数：void
* 输出参数：void
* 返 回 值：void
* 创建日期：2025年04月25日
* 注    意：
*********************************************************************************************************/
static void ConfigRCU(void)
{
    //使能GPIOA，ADC0，DMA0，TIMER0时钟
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6);
    rcu_periph_clock_enable(RCU_ADC0);
    rcu_periph_clock_enable(RCU_DMA0);
    rcu_periph_clock_enable(RCU_TIMER0);
}

/*********************************************************************************************************
* 函数名称：ConfigDMA0CH0ForADC0
* 函数功能：配置DMA0CH0ForADC0
* 输入参数：void
* 输出参数：void
* 返 回 值：void
* 创建日期：2025年04月25日
* 注    意：
*********************************************************************************************************/
static void ConfigDMA0CH0ForADC0()
{
    //DMA配置结构体
    dma_parameter_struct dma_struct;

    //配置DMA1_CH2
    dma_deinit(DMA0, DMA_CH0);                                  //复位DMA
//    dma_struct_para_init(&dma_struct);                          //复位配置结构体
    
    dma_struct.direction = DMA_PERIPHERAL_TO_MEMORY;            //传输方向为外设到内存
    dma_struct.memory_addr = (uint32_t)&s_arrADCData;           //内存地址
    dma_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;         //内存地址增长
    dma_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;           //内存数据宽度为16位
    dma_struct.number = 1;                                      //传输数据量
    dma_struct.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));      //外设地址
    dma_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;        //外设地址增长关闭
    dma_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;       //外设数据位宽为16位
    dma_struct.priority = DMA_PRIORITY_ULTRA_HIGH;              //高优先级
    dma_init(DMA0, DMA_CH0, &dma_struct);                       //根据参数配置DMA0_CH0
    
    //DMA模式设置
    dma_circulation_enable(DMA0, DMA_CH0);                      //开启循环模式
    dma_memory_to_memory_disable(DMA0, DMA_CH0);                //失能内存到内存
    nvic_irq_enable(DMA0_Channel0_IRQn, 1, 1);                  //中断线配置
    dma_interrupt_enable(DMA0, DMA_CH0, DMA_INT_FTF);           //使能DMA中断                       
    
    //使能DMA0_CH0
    dma_channel_enable(DMA0, DMA_CH0);
}

/*********************************************************************************************************
* 函数名称：ConfigTIMER0
* 函数功能：配置TIMER0
* 输入参数：void
* 输出参数：void
* 返 回 值：void
* 创建日期：2025年04月25日
* 注    意：
*********************************************************************************************************/
static void ConfigTIMER0(unsigned short arr, unsigned short psc)
{
    timer_oc_parameter_struct timer_ocinitpara;          //timer_ocinitpara用于存放输出配置
    timer_parameter_struct timer_initpara;               //timer_initpara用于存放定时器的参数

    timer_deinit(TIMER0);                                //设置TIMER0参数恢复默认值
//    timer_struct_para_init(&timer_initpara);             //初始化timer_initpara

    //配置TIMER0
    timer_initpara.prescaler         = psc;                 //设置预分频器值
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;  //设置对齐模式
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;    //设置向上计数模式
    timer_initpara.period            = arr;                 //设置自动重装载值
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;    //设置时钟分割
    timer_initpara.repetitioncounter = 0;                   //设置重复计数值
    timer_init(TIMER0, &timer_initpara);                    //根据参数初始化定时器
    
    //将结构体参数初始化为默认值
//    timer_channel_output_struct_para_init(&timer_ocinitpara);
    
    timer_ocinitpara.ocpolarity    = TIMER_OC_POLARITY_LOW;             //设置通道输出极性    
    timer_ocinitpara.outputstate   = TIMER_CCX_ENABLE;                  //设置通道输出状态
    timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocinitpara); //初始化结构体
    
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 100);              //设置占空比
    timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM1);       //设置通道比较模式
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);//失能比较影子寄存器
    
    timer_channel_control_shadow_config(TIMER0, DISABLE);                           //失能通道换相控制影子寄存器
    timer_auto_reload_shadow_enable(TIMER0);                                        //自动重载影子寄存器使能
    timer_primary_output_config(TIMER0, ENABLE);                                    //TIMER0通道输出使能
    
    timer_enable(TIMER0);                                                           //使能定时器
}

/*********************************************************************************************************
* 函数名称：ConfigADC0
* 函数功能：配置ADC0
* 输入参数：void
* 输出参数：void
* 返 回 值：void
* 创建日期：2025年04月25日
* 注    意：
*********************************************************************************************************/
static void ConfigADC0(void)
{
    //ADC0引脚配置（PA3）
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
    
    //ADC0通道数目设置
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);
    
    //通道1配置
    adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_3, ADC_SAMPLETIME_239POINT5);
    
    //使能外部触发
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
    
    //选择外部触发源
    adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T0_CH0); 
    
    //设置数据对齐方式
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    
    //使能ADC0
    adc_enable(ADC0);
    
    //ADC校准
    DelayNms(5);
    adc_calibration_enable(ADC0);
    DelayNms(5);
    
    //使能ADC0的DMA功能
    adc_dma_mode_enable(ADC0);
}

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称：InitADC
* 函数功能：初始化ADC模块
* 输入参数：void
* 输出参数：void
* 返 回 值：void
* 创建日期：2025年04月25日
* 注    意：
*********************************************************************************************************/
void InitADC(void)
{
    //时钟配置
    ConfigRCU();
    
    //DMA0配置
    ConfigDMA0CH0ForADC0();
    
    //TIMER0配置
    ConfigTIMER0(7999, 119);
    
    //ADC0配置
    ConfigADC0();
    
}

void DMA0_Channel0_IRQHandler(void)
{
    if(RESET != dma_interrupt_flag_get(DMA0,DMA_CH0,DMA_INT_FLAG_FTF)){
        adcVol = (uint16_t)(s_arrADCData * 1000 * 3.275 / 4096);
        //清除标志位
        dma_interrupt_flag_clear(DMA0,DMA_CH0,DMA_INT_FLAG_FTF);
    }        
}

uint16_t getAdcVol(void)
{
    return adcVol;
}
